package br.com.estevam.sisfin.daos;

import java.util.Date;
import java.util.List;

import org.apache.tapestry5.hibernate.HibernateSessionManager;
import org.apache.tapestry5.services.ApplicationStateManager;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import br.com.estevam.sisfin.data.Visit;
import br.com.estevam.sisfin.entities.AbstractEntity;
import br.com.estevam.sisfin.enums.OrderEnums;

public class AbstractDAOImpl {

	protected HibernateSessionManager hsm;
	protected ApplicationStateManager asm;
	protected Class<?> entity;

	public AbstractDAOImpl(HibernateSessionManager hsm, ApplicationStateManager asm, Class<?> entity){
		this.hsm = hsm;
		this.asm = asm;
		this.entity = entity;
	}
	
	protected void getIdUsuario(AbstractEntity entity){
		entity.setUserId(asm.get(Visit.class).getId());
	}
	
	protected Criteria createCriteria(){
		return hsm.getSession().createCriteria(entity);
	}
	
	protected Criteria addEqRestriction(Criteria c, String fieldName, Object value){
		if(value instanceof Double) {
			c = addEqRestriction(c, fieldName, ((Double)value).doubleValue());
		} else if(value instanceof Long) {
			c = addEqRestriction(c, fieldName, ((Long)value).longValue());
		} else if(value instanceof Float) {
			c = addEqRestriction(c, fieldName, ((Float)value).floatValue());
		} else if(value instanceof Integer) {
			c = addEqRestriction(c, fieldName, ((Integer)value).intValue());
		} else if(value instanceof Date) {
			c = addEqRestriction(c, fieldName, ((Date)value));
		} else if(value == null) {
			c = addEqRestriction(c, fieldName, "");
		} else {
			c = addEqRestriction(c, fieldName, value.toString());
		}
		
		return c;
	}
	
	protected Criteria setEagerFetch(Criteria c, String propertyToFetch){
		return c.setFetchMode(propertyToFetch, FetchMode.JOIN);
	}
	
	protected Criteria addOrder(Criteria c, String fieldName, OrderEnums orderType){
		if(orderType == OrderEnums.ASC_ORDER){
			c.addOrder(Order.asc(fieldName));
		} else if(orderType == OrderEnums.DESC_ORDER){
			c.addOrder(Order.desc(fieldName));
		} else if(orderType == OrderEnums.NO_ORDER){
			//do nothing.
		}
		return c;
	}
	
	private Criteria addEqRestriction(Criteria c, String fieldName, String value){
		if(value != null && !value.toString().trim().equalsIgnoreCase("")){
			c.add(Restrictions.eq(fieldName, value.toString()));
		}
		return c;
	}
	
	private Criteria addEqRestriction(Criteria c, String fieldName, int value){
		if(value > 0){
			c.add(Restrictions.eq(fieldName, value));
		}
		return c;
	}
	
	private Criteria addEqRestriction(Criteria c, String fieldName, long value){
		if(value > 0){
			c.add(Restrictions.eq(fieldName, value));
		}
		return c;
	}
	
	private Criteria addEqRestriction(Criteria c, String fieldName, double value){
		if(value > 0){
			c.add(Restrictions.eq(fieldName, value));
		}
		return c;
	}
	
	private Criteria addEqRestriction(Criteria c, String fieldName, Date value){
		if(value != null){
			c.add(Restrictions.eq(fieldName, value));
		}
		return c;
	}

	public void add(AbstractEntity entity) {
		getIdUsuario(entity);
		hsm.getSession().persist(entity);
	}
	
	public long addGetIdentifier(AbstractEntity entity) {
		getIdUsuario(entity);
		hsm.getSession().persist(entity);
		return Long.parseLong(hsm.getSession().getIdentifier(entity).toString());
	}

	public void addOrUpdate(AbstractEntity entity) {
		getIdUsuario(entity);
		hsm.getSession().saveOrUpdate(entity);
	}
	
	public long addGetIdentifierOrUpdate(AbstractEntity entity) {
		getIdUsuario(entity);
		hsm.getSession().saveOrUpdate(entity);
		return Long.parseLong(hsm.getSession().getIdentifier(entity).toString());
	}

	public void update(AbstractEntity entity) {
		getIdUsuario(entity);
		hsm.getSession().update(entity);
	}

	public void delete(AbstractEntity entity) {
		getIdUsuario(entity);
		hsm.getSession().delete(entity);
	}
	
	public Object findById(long id) {
		return createCriteria().add(Restrictions.idEq(id)).uniqueResult();
	}
	
	public List<?> findAll() {
		return createCriteria().list();
	}
	
	public List<?> findAllOrderBy(String fieldName, OrderEnums orderType) {
		Criteria c = createCriteria();
		c = addOrder(c, fieldName, orderType);
		return c.list();
	}
	
	public int rowCountAll(){
		Criteria c = createCriteria();
		c.setProjection(Projections.rowCount());
		return (Integer) c.uniqueResult();
	}
	
	public int count(String fieldName, Object whereEqualsTo){
		Criteria c = createCriteria();
		c = addEqRestriction(c, fieldName, whereEqualsTo);
		c.setProjection(Projections.count(fieldName));
		
		return (Integer) c.uniqueResult();
	}
	
	public void about(){
		hsm.abort();
	}
	
	public void commit(){
		hsm.commit();
	}

}
